//
//  main.c
//  slist
//
//  Created by chenyh on 2021/1/26.
//

#include <stdio.h>
#include "slist.h"
#include <stdlib.h>
#include <time.h>
typedef struct _slist_int {
    slist_node_t node; //包含链表结点
    int data;          //int类型数据
}slist_int_t;
/**
 将结点定义到学生信息中可以使用链表来管理，但却存在一个很严重的问题，
 因为修改了学生记录类型的定义，就会影响所有使用该记录结构体类型的程序模块。
 在实际的应用上，学生记录可以用链表管理，也可以用数组管理，当使用数组管理时，
 则又要重新修改学生记录的类型。而node仅仅是链表的结点，与学生记录没有任何关系。
 不能讲node直接放在学生记录结构体中。应该使他们分离。基于此，需要定义一个新的
 结构体类型，将学生记录和node关联起来，使得可以用链表来管理学生记录。
 */
typedef struct _student{
    char    name[10];
    char    sex;
    float   height,weight;
}student_t;

typedef struct _slist_student{
    slist_node_t node;  //包含链表结点
    student_t   student; //学生记录
}slist_student_t;

int student_info_read(student_t *p_student) //读取学生记录,随机产生,仅供测试
{
    int i;
    
    for (i = 0; i < 9; i++) {
        p_student->name[i] = (rand() % ('z'-'a')) + 'a';
    }
    p_student->name[i] = '\0'; //字符串结束符;
    p_student->sex     = (rand() & 0x01) ? 'F':'M'; //随机性别
    p_student->height  = (float)rand()/rand();
    p_student->weight = (float)rand()/rand();
    return 0;
}

int list_node_process (void *p_arg, slist_node_t *p_node)
{
    student_t *p_s = &(((slist_student_t *)p_node)->student);
    printf("%s : %c %.2f %.2f\n", p_s->name, p_s->sex, p_s->height, p_s->weight);
    return  0;
}
int my_list_add(slist_head_t *p_head,int data) //插入一个数据
{
    slist_int_t *p_node = (slist_int_t *)malloc(sizeof(slist_int_t));
    if (p_node == NULL) {
        printf("The malloc memory failed!");
        return -1;
    }
    p_node->data = data;
    slist_add_head(p_head, &(p_node->node)); //将结点加入链表中
    return 0;
}
int my_list_del(slist_head_t *p_head,int data) //删除一条数据
{
    slist_node_t *p_node = slist_begin_get(p_head);
    slist_node_t *p_end = slist_end_get(p_head);
    while (p_node != p_end) {
        if (((slist_int_t *)p_node)->data == data) {
            printf("\n delete the data %d",data);
            slist_del(p_head, p_node);
            free(p_node);
            break;
        }
        p_node = slist_next_get(p_head, p_node);
    }
//    slist_foreach(p_head, list_node_process, NULL); //删除结点后,再打印出所有结点的数据信息
    return  0;
}
           
int main(int argc, const char * argv[]) {
    slist_head_t p_head;
    slist_student_t s1,s2,s3,s4,s5;
    srand(time(NULL));
    slist_init(&p_head);
    student_info_read(&s1.student);
    student_info_read(&s2.student);
    student_info_read(&s3.student);
    student_info_read(&s4.student);
    student_info_read(&s5.student);
    
    slist_add_head(&p_head, &s1.node);
    slist_add_head(&p_head, &s2.node);
    slist_add_head(&p_head, &s3.node);
    slist_add_head(&p_head, &s4.node);
    slist_add_head(&p_head, &s5.node);
    slist_foreach(&p_head, list_node_process, NULL);
    
    return 0;
}
/**
 综上所述，虽然链表比数组更灵活，很容易在链表中插入和删除结点，但也失去了
 数组的“随机访问”能力。
 如果结点距链表的开始处很近，那么访问它就会很快；
 如果结点靠近链表的结尾处，则访问它就会很慢。
 但单项链表也存在不能“回溯”的缺点，即在向链表中插入结点时，必须知道插入结点前面的结点；
 从链表中删除结点时，必须知道被删除结点前面的结点；
 很难逆向遍历链表。如果是双向链表，就可以解决这些问题。
 
 */
